package com.invengo.module_check.ui.fragment.widget;

import android.annotation.SuppressLint;
import android.app.Application;
import android.os.Build;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableField;
import androidx.databinding.ObservableList;
import androidx.recyclerview.widget.GridLayoutManager;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.invengo.base.utils.CompressUtil;
import com.invengo.library_db.GreenDaoManager;
import com.invengo.library_db.entity.module_check.ColumBean;
import com.invengo.library_db.entity.module_check.ShelfBean;
import com.invengo.library_db.entity.module_check.ShelfJson;
import com.invengo.library_db.entity.module_check.StructBean;
import com.invengo.module_check.BR;
import com.invengo.module_check.R;
import com.invengo.module_check.data.repsitory.offlinedata.NetModelRepsitory;
import com.invengo.module_check.ui.fragment.widget.adapter.RoomAdapter;
import com.invengo.module_check.ui.fragment.widget.adapter.RowAdapter;
import com.invengo.module_check.ui.fragment.widget.adapter.ShelfAdapter;
import com.invengo.module_check.ui.fragment.widget.item.RoomItemViewModel;
import com.invengo.module_check.ui.fragment.widget.item.RowItemViewModel;
import com.invengo.module_check.ui.fragment.widget.item.ShelfItemViewModel;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;

import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import java8.util.Comparators;
import java8.util.stream.StreamSupport;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.bus.event.SingleLiveEvent;
import me.goldze.mvvmhabit.http.BaseBean;
import me.goldze.mvvmhabit.utils.KLog;
import me.goldze.mvvmhabit.utils.RxUtils;
import me.tatarka.bindingcollectionadapter2.ItemBinding;
import me.tatarka.bindingcollectionadapter2.collections.MergeObservableList;

public class SelectShelfViewModel extends BaseViewModel<NetModelRepsitory> {
    private ShelfBean defaultBean;
    public RoomAdapter roomAdapter = new RoomAdapter();
    public RowAdapter RowAdapter = new RowAdapter();
    public ShelfAdapter shelAdapter = new ShelfAdapter();
    public ObservableField<GridLayoutManager> manager = new ObservableField<>(new GridLayoutManager(getApplication(), 3));

    public ObservableList<String> libraryItems = new ObservableArrayList<>();

    public ObservableList<RowItemViewModel> rowItemList = new ObservableArrayList<>();
    public ItemBinding<RowItemViewModel> rowItemBinding = ItemBinding.of(BR.viewModel, R.layout.item_dialog_shelf_row);

    public ObservableList<ShelfItemViewModel> shelfItemList = new ObservableArrayList<>();
    public ItemBinding<ShelfItemViewModel> shelfItemBinding = ItemBinding.of(BR.viewModel, R.layout.item_dialog_shelf_info);

    public SingleLiveEvent<ShelfBean> shelfBean = new SingleLiveEvent<>();
    public ObservableField<String> selectValue = new ObservableField<>();
    //    mutableListOf
    public MergeObservableList<Object> roomItemList = new MergeObservableList<>();

    //给RecyclerView添加ItemBinding
    public ItemBinding<Object> roomItemBinding = ItemBinding.of((itemBinding, position, item) -> {
        if (item.getClass().equals(String.class)) {
            itemBinding.set(BR.title, R.layout.item_dialog_select_area_title);
        } else if (item.getClass().equals(RoomItemViewModel.class)) {
            itemBinding.set(BR.viewModel, R.layout.item_dialog_select_area);
        }
    });

    TreeMap<String, List<StructBean>> structMaps = new TreeMap<>();
    List<ColumBean> columData = new ArrayList<>();


    public SelectShelfViewModel(@NonNull Application application) {
        super(application, NetModelRepsitory.getInstance());
        manager.get().setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                return roomItemList.get(position).getClass().equals(String.class) ? 3 : 1;
            }
        });
    }

    public BindingCommand<String> onLibrarySelectCommand = new BindingCommand<>(name -> {
        if (defaultBean != null) {
            clickLibrary(defaultBean.getBuildingName());
        } else {
            clickLibrary(name);
        }
    });


    public UIChangeObservable uc = new UIChangeObservable();


    public class UIChangeObservable {
        public SingleLiveEvent<Integer> roomMoveEvent = new SingleLiveEvent<>();
        public SingleLiveEvent<ShelfBean> closeEvent = new SingleLiveEvent<>();
        public SingleLiveEvent<Integer> rowMoveEvent = new SingleLiveEvent<>();
        public SingleLiveEvent<Integer> shelfMoveEvent = new SingleLiveEvent<>();
        public SingleLiveEvent<Boolean> downloadDialogEvent = new SingleLiveEvent<>();
        public SingleLiveEvent<Integer> downloadProgressEvent = new SingleLiveEvent<>();
        public SingleLiveEvent<String> downloadContentEvent = new SingleLiveEvent<>();
    }

    /**
     * 更新对话框
     *
     * @param content  所容纳之物
     * @param progress 进步
     */
    private double minProgress = 0;

    private void updateDialog(String content, double progress) {
        uc.downloadContentEvent.postValue(content);
        minProgress += progress;
        if (minProgress > 1) {
            double floor = Math.floor(minProgress);
            minProgress -= floor;
            uc.downloadProgressEvent.postValue((int) floor);
        }
    }

    public void loadShelfData(ShelfBean defaultShelfBean) {
        this.defaultBean = defaultShelfBean;
        if (defaultShelfBean == null) {
            RowAdapter.setSelectPosition(0);
            shelAdapter.setSelectPosition(0);
        }
        if (model.getStructData().isEmpty()) {
            model.getStruct()
                    .compose(RxUtils.applySchedulersLoading(getLifecycleProvider(), this))
                    .observeOn(AndroidSchedulers.mainThread())
                    .doOnSubscribe(disposable -> {
                        uc.downloadDialogEvent.postValue(true);
                        updateDialog("楼层数据下载..", 10);
                    })
                    .observeOn(Schedulers.io())
                    .doOnNext(structBeans -> {
                        updateDialog("清除楼层数据..", 10);
                        GreenDaoManager.getInstance().cleanAllStruct();
                    })
                    .doOnNext(structBeans -> {
                        updateDialog("楼层数据存储..", 10);
                        List<StructBean> collect = null;
                        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
                            collect = structBeans.stream().filter(structBean -> !TextUtils.isEmpty(structBean.getRoomName())).collect(Collectors.toList());
                        } else {
                            collect = StreamSupport.stream(structBeans).filter(structBean -> !TextUtils.isEmpty(structBean.getRoomName())).collect(java8.util.stream.Collectors.toList());

                        }
                        model.saveStruct2DB(collect);
                    })
                    .flatMap((Function<List<StructBean>, ObservableSource<BaseBean<ShelfJson>>>) structBeans -> {
                        updateDialog("获取层位数据..", 10);
                        return model.getAllShelf();
                    })
                    .map(shelfJsonBaseBean -> {
                        updateDialog("数据解密..", 10);
                        return shelfJsonBaseBean.getData();
                    })
                    .map(rfidDataDto -> {
                        updateDialog("数据解析..", 10);
                        return new Gson().fromJson(CompressUtil.decompresss(rfidDataDto.getData()), new TypeToken<List<ShelfBean>>() {
                        }.getType());
                    })
                    .map(shelfBeans -> {
                        updateDialog("数据转换..", 10);
                        return transShelfBean((List<ShelfBean>) shelfBeans);
                    })
                    .doOnNext(shelfBeans -> {
                        updateDialog("数据存储..", 10);
                        model.insertSelfInfo(shelfBeans);
                    })
                    .doOnNext(shelfBeans -> {
                        updateDialog("删除排位信息..", 10);
                        model.removeAllColum();
                    })
                    .map(shelfBeans -> {
                        updateDialog("排位解析..", 10);
                        return transColums(shelfBeans);
                    })
                    .doOnNext(columBeans -> {
                        updateDialog("排位存储..", 10);
                        model.insertCoumBneas(columBeans);
                    })
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(size -> {
                        uc.downloadDialogEvent.postValue(false);
                        initLibrary(model.getStructData());
                    });
        } else {
            initLibrary(model.getStructData());
        }
    }


    private List<ColumBean> transColums(List<ShelfBean> shelfBeans) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return shelfBeans.parallelStream().map(bean -> {
                ColumBean columBean = new ColumBean();
                try {
                    columBean.setColumName(bean.getColumName());
                    columBean.setColumSortName(bean.getColumName().split("__")[1]);
                    columBean.setColumNum(Integer.parseInt(columBean.getColumSortName().replace("排", "").replace("架", "")));
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
                return columBean;
            }).collect(Collectors.collectingAndThen(
                    Collectors.toCollection(() -> new TreeSet<>(
                            Comparator.comparing(p -> p.getColumName()))), ArrayList::new));
        } else {
            return StreamSupport.parallelStream(shelfBeans).map(bean -> {
                ColumBean columBean = new ColumBean();
                try {
                    columBean.setColumName(bean.getColumName());
                    columBean.setColumSortName(bean.getColumName().split("__")[1]);
                    columBean.setColumNum(Integer.parseInt(columBean.getColumSortName().replace("排", "").replace("架", "")));
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
                return columBean;
            }).collect(java8.util.stream.Collectors.collectingAndThen(
                    java8.util.stream.Collectors.toCollection(() -> new TreeSet<>(
                            Comparators.comparing(p -> p.getColumName()))), ArrayList::new));
        }
    }


    private List<ShelfBean> transShelfBean(List<ShelfBean> shelfBeans) {
        List<StructBean> allStruct = GreenDaoManager.getInstance().getAllStruct();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return shelfBeans.stream().map(shelfBean -> {
                int buildNo = Integer.parseInt(shelfBean.getShelfCode().substring(0, 2));
                int floorNo = Integer.parseInt(shelfBean.getShelfCode().substring(2, 4));
                int roomNo = Integer.parseInt(shelfBean.getShelfCode().substring(4, 6));
                allStruct.stream().filter(it -> it.getBuildNo() == buildNo && floorNo == it.getFloorNo() && roomNo == it.getRoomNo()).findFirst().ifPresent(structBean -> {
                    shelfBean.BuildNo = structBean.getBuildNo();
                    shelfBean.FloorNo = structBean.getFloorNo();
                    shelfBean.RoomNo = structBean.getRoomNo();
                    shelfBean.BuildingName = structBean.getBuildingName();
                    shelfBean.FloorName = structBean.getFloorName();
                    shelfBean.RoomName = structBean.getRoomName();
                    shelfBean.setColumName(structBean.getBuildingName() + structBean.getFloorName() + structBean.getRoomName() + "__" + getLayerName(shelfBean));
                });
                return shelfBean;
            }).collect(Collectors.toList());
        } else {
            return StreamSupport.stream(shelfBeans).map(shelfBean -> {
                int buildNo = Integer.parseInt(shelfBean.getShelfCode().substring(0, 2));
                int floorNo = Integer.parseInt(shelfBean.getShelfCode().substring(2, 4));
                int roomNo = Integer.parseInt(shelfBean.getShelfCode().substring(4, 6));
                StreamSupport.stream(allStruct).filter(it -> it.getBuildNo() == buildNo && floorNo == it.getFloorNo() && roomNo == it.getRoomNo()).findFirst().ifPresent(structBean -> {
                    shelfBean.BuildNo = structBean.getBuildNo();
                    shelfBean.FloorNo = structBean.getFloorNo();
                    shelfBean.RoomNo = structBean.getRoomNo();
                    shelfBean.BuildingName = structBean.getBuildingName();
                    shelfBean.FloorName = structBean.getFloorName();
                    shelfBean.RoomName = structBean.getRoomName();
                    shelfBean.setColumName(structBean.getBuildingName() + structBean.getFloorName() + structBean.getRoomName() + "__" + getLayerName(shelfBean));
                });
                return shelfBean;
            }).collect(java8.util.stream.Collectors.toList());
        }
    }

    private String getLayerName(ShelfBean bean) {
        String layerName = "";
        try {
            if (bean.getShelfName().isEmpty())
                return "未知";
            String replace = bean.getShelfName().replace(bean.getBuildingName(), "").replace(bean.getFloorName(), "").replace(bean.getRoomName(), "");
            if (replace.indexOf("架") > 0)
                layerName = replace.substring(0, replace.indexOf("架") + 1);
            if (TextUtils.isEmpty(layerName))
                if (replace.indexOf("排") > 0)
                    layerName = replace.substring(0, replace.indexOf("排") + 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return layerName;
    }

    private void initShelfBean(ShelfBean bean, List<StructBean> structBeans) {
        int buildNo = Integer.parseInt(bean.getShelfCode().substring(0, 2));
        int floorNo = Integer.parseInt(bean.getShelfCode().substring(2, 4));
        int roomNo = Integer.parseInt(bean.getShelfCode().substring(4, 6));
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            structBeans.stream().filter(it -> it.getBuildNo() == buildNo && floorNo == it.getFloorNo() && roomNo == it.getRoomNo()).findFirst().ifPresent(structBean -> {
                bean.BuildNo = structBean.getBuildNo();
                bean.FloorNo = structBean.getFloorNo();
                bean.RoomNo = structBean.getRoomNo();
                bean.BuildingName = structBean.getBuildingName();
                bean.FloorName = structBean.getFloorName();
                bean.RoomName = structBean.getRoomName();
                bean.setColumName(structBean.getBuildingName() + structBean.getFloorName() + structBean.getRoomName() + "__" + getLayerName(bean));
            });
        } else {
            StreamSupport.stream(structBeans).filter(it -> it.getBuildNo() == buildNo && floorNo == it.getFloorNo() && roomNo == it.getRoomNo()).findFirst().ifPresent(structBean -> {
                bean.BuildNo = structBean.getBuildNo();
                bean.FloorNo = structBean.getFloorNo();
                bean.RoomNo = structBean.getRoomNo();
                bean.BuildingName = structBean.getBuildingName();
                bean.FloorName = structBean.getFloorName();
                bean.RoomName = structBean.getRoomName();
                bean.setColumName(structBean.getBuildingName() + structBean.getFloorName() + structBean.getRoomName() + "__" + getLayerName(bean));
            });
        }
    }

    private void initLibrary(List<StructBean> structBeans) {
        if (defaultBean != null)
            initShelfBean(defaultBean, structBeans);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            structMaps = structBeans.stream().collect(Collectors.groupingBy(StructBean::getBuildingName, TreeMap::new, Collectors.toList()));
        } else {
            structMaps = StreamSupport.stream(structBeans).collect(java8.util.stream.Collectors.groupingBy(StructBean::getBuildingName, TreeMap::new, java8.util.stream.Collectors.toList()));
        }
        for (String s : structMaps.keySet()) {
            libraryItems.add(s);
        }
    }

    private void clickLibrary(String libraryName) {
        StructBean clickStructBean = null;
        if (defaultBean != null) {
            clickStructBean = model.getStructByShelf(defaultBean);
        }
        roomItemList.removeAll();
        TreeMap<String, List<StructBean>> floors = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            floors = structMaps.get(libraryName)
                    .stream()
                    .collect(Collectors.groupingBy(StructBean::getFloorName, TreeMap::new, Collectors.toList()));
        } else {
            floors = StreamSupport.stream(structMaps.get(libraryName))
                    .collect(java8.util.stream.Collectors.groupingBy(StructBean::getFloorName, TreeMap::new, java8.util.stream.Collectors.toList()));
        }
        StructBean roomBean = null;
        for (Map.Entry<String, List<StructBean>> entry : floors.entrySet()) {
            roomItemList.insertItem(entry.getKey());
            ObservableList<RoomItemViewModel> list = new ObservableArrayList<>();
            for (StructBean structBean : entry.getValue()) {
                if (roomBean == null) {
                    roomBean = clickStructBean != null ? clickStructBean : structBean;
                }
                list.add(new RoomItemViewModel(this, structBean));
                if (structBean.getFloorNo() == roomBean.getFloorNo() && structBean.getRoomNo() == roomBean.getRoomNo()) {
                    int position = roomItemList.size() + list.size() - 1;
                    roomAdapter.setSelectPosition(position);
                }
            }
            roomItemList.insertList(list);
        }

        if (defaultBean != null) {
            uc.roomMoveEvent.postValue(roomAdapter.getSelectPosition());
            clickRoom(model.getStructByShelf(defaultBean));
        } else {
            clickRoom(roomBean);
        }
    }


    public void roomItemClick(RoomItemViewModel itemViewModel) {
        int position = roomItemList.indexOf(itemViewModel);
        int tempPosition = roomAdapter.getSelectPosition();
        roomAdapter.setSelectPosition(position);
        roomAdapter.notifyItemChanged(tempPosition);
        roomAdapter.notifyItemChanged(position);
        StructBean value = itemViewModel.roomStruce.getValue();
        cleanDefault();
        clickRoom(value);
    }


    private void clickRoom(StructBean structBean) {
        rowItemList.clear();
        columData = model.getColumData(structBean);
        String rowName = "";
        for (ColumBean bean : columData) {
            if (TextUtils.isEmpty(rowName))
                rowName = bean.getColumSortName();
            rowItemList.add(new RowItemViewModel(this, bean));
        }
        if (defaultBean != null) {
            uc.rowMoveEvent.postValue(RowAdapter.getSelectPosition());
            String defaultRow = defaultBean.getColumName().split("__")[1];
            clickRow(defaultRow);
        } else {
            clickRow(rowName);
        }
    }

    private void cleanDefault() {
        defaultBean = null;
    }


    public void rowItemClick(RowItemViewModel itemViewModel) {
        int position = rowItemList.indexOf(itemViewModel);
        int tempPosition = RowAdapter.getSelectPosition();
        RowAdapter.setSelectPosition(position);
        RowAdapter.notifyItemChanged(tempPosition);
        RowAdapter.notifyItemChanged(position);
        ColumBean value = itemViewModel.bean.getValue();
        cleanDefault();
        clickRow(value.getColumSortName());
    }

    public void clickRow(String rowName) {
        shelfItemList.clear();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            columData.stream()
                    .filter(bean -> bean.getColumSortName().equals(rowName))
                    .findFirst()
                    .map(bean -> bean.getShelfBeans())
                    .ifPresent(shelfBeans -> {
                        ShelfBean bean = defaultBean;
                        for (int i = 0; i < shelfBeans.size(); i++) {
                            if (bean == null)
                                bean = shelfBeans.get(i);
                            shelfItemList.add(new ShelfItemViewModel(SelectShelfViewModel.this, shelfBeans.get(i)));
                            if (shelfBeans.get(i).getShelfCode().equals(bean.getShelfCode())) {
                                shelAdapter.setSelectPosition(i);
                            }
                        }
                        if (defaultBean != null) {
                            KLog.e("-----------" + shelAdapter.getSelectPosition());
                            uc.shelfMoveEvent.postValue(shelAdapter.getSelectPosition());
                        }
                        clickShelf(bean);
                    });
        } else {
            StreamSupport.stream(columData)
                    .filter(bean -> bean.getColumSortName().equals(rowName))
                    .findFirst()
                    .map(bean -> bean.getShelfBeans())
                    .ifPresent(shelfBeans -> {
                        ShelfBean bean = defaultBean;
                        for (int i = 0; i < shelfBeans.size(); i++) {
                            if (bean == null)
                                bean = shelfBeans.get(i);
                            shelfItemList.add(new ShelfItemViewModel(SelectShelfViewModel.this, shelfBeans.get(i)));
                            if (shelfBeans.get(i).getShelfCode().equals(bean.getShelfCode())) {
                                shelAdapter.setSelectPosition(i);
                            }
                        }
                        if (defaultBean != null) {
                            KLog.e("-----------" + shelAdapter.getSelectPosition());
                            uc.shelfMoveEvent.postValue(shelAdapter.getSelectPosition());
                        }
                        clickShelf(bean);
                    });
        }
    }


    public void shelfItemClick(ShelfItemViewModel itemViewModel) {
        int position = shelfItemList.indexOf(itemViewModel);
        int tempPosition = shelAdapter.getSelectPosition();
        shelAdapter.setSelectPosition(position);
        shelAdapter.notifyItemChanged(tempPosition);
        shelAdapter.notifyItemChanged(position);
        ShelfBean value = itemViewModel.bean.getValue();
        cleanDefault();
        clickShelf(value);
    }


    public void clickShelf(ShelfBean bean) {
        shelfBean.postValue(bean);
    }

    public BindingCommand conform = new BindingCommand(() -> {
        uc.closeEvent.postValue(shelfBean.getValue());
    });
}
